﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace CrazyDrawShape
{
    /// <summary>
    /// DrawRectangleControl.xaml 的交互逻辑
    /// </summary>
    public partial class DrawRectangleControl : UserControl
    {
        private enum DrawType
        {
            Draw,
            Edit
        }
        private enum EditType
        {
            Left,
            Top, 
            Right,
            Bottom,
            LeftTop,
            RightTop,
            LeftBottom,
            RightBottom,
            Internal,
            None
        }
        Path box = new Path { Stroke = Brushes.Red, StrokeThickness = 2, Fill = Brushes.AliceBlue, Opacity = 0.5, ClipToBounds = true };
        bool isDown = false;
        Point downPoint;
        DrawType drawType = DrawType.Draw;
        EditType editType = EditType.None;
        
        public DrawRectangleControl()
        {
            InitializeComponent();
        }

        private void DrawClick(object sender, RoutedEventArgs e)
        {
            this.drawType = DrawType.Draw;
        }

        private void EditClick(object sender, RoutedEventArgs e)
        {
            this.drawType = DrawType.Edit;
        }

        private double PPDistance(Point p1, Point p2)
        {
            return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
        }

        private EditType GetEditType(Point point)
        {
            RectangleGeometry rect = (RectangleGeometry)this.box.Data;
            double distance = 5;
            if (PPDistance(point, rect.Rect.TopLeft) < distance)
            {
                return EditType.LeftTop;
            }
            else if (PPDistance(point, rect.Rect.TopRight) < distance)
            {
                return EditType.RightTop;
            }
            else if (PPDistance(point, rect.Rect.BottomLeft) < distance)
            {
                return EditType.LeftBottom;
            }
            else if (PPDistance(point, rect.Rect.BottomRight) < distance)
            {
                return EditType.RightBottom;
            }
            else if (point.X > rect.Rect.Left - distance && point.X < rect.Rect.Left + distance && point.Y > rect.Rect.Top && point.Y < rect.Rect.Bottom)
            {
                return EditType.Left;
            }
            else if (point.X > rect.Rect.Right - distance && point.X < rect.Rect.Right + distance && point.Y > rect.Rect.Top && point.Y < rect.Rect.Bottom)
            {
                return EditType.Right;
            }
            else if (point.Y > rect.Rect.Top - distance && point.Y < rect.Rect.Top + distance && point.X > rect.Rect.Left && point.X < rect.Rect.Right)
            {
                return EditType.Top;
            }
            else if (point.Y > rect.Rect.Bottom - distance && point.Y < rect.Rect.Bottom + distance && point.X > rect.Rect.Left && point.X < rect.Rect.Right)
            {
                return EditType.Bottom;
            }
            else if (point.X > rect.Rect.Left && point.X < rect.Rect.Right && point.Y > rect.Rect.Top && point.Y < rect.Rect.Bottom)
            {
                return EditType.Internal;
            }
            else
            {
                return EditType.None;
            }
        }

        private void GridMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.downPoint = e.GetPosition(mainGrid);
                this.isDown = true;
                switch (this.drawType)
                {
                    case DrawType.Draw:
                        mainGrid.Children.Clear();
                        mainGrid.Children.Add(this.box);
                        this.box.Data = null;
                        break;
                    case DrawType.Edit:
                        this.editType = GetEditType(this.downPoint);
                        break;
                }
            }
        }

        private void GridMouseUp(object sender, MouseButtonEventArgs e)
        {
            this.isDown = false;
            this.editType = EditType.None;
        }

        private void GridMouseMove(object sender, MouseEventArgs e)
        {
            if (this.isDown)
            {
                switch (this.drawType)
                {
                    case DrawType.Draw:
                        this.box.Data = new RectangleGeometry { Rect = new Rect(this.downPoint, e.GetPosition(mainGrid)) };
                        break;
                    case DrawType.Edit:
                        Point curPoint = e.GetPosition(mainGrid);
                        switch (this.editType)
                        {
                            case EditType.Left:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(new Point(curPoint.X, ((RectangleGeometry)this.box.Data).Rect.Top),
                                   ((RectangleGeometry)this.box.Data).Rect.BottomRight)
                                };
                                break;
                            case EditType.Top:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(new Point(((RectangleGeometry)this.box.Data).Rect.Left, curPoint.Y),
                                  ((RectangleGeometry)this.box.Data).Rect.BottomRight)
                                };
                                break;
                            case EditType.Right:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(((RectangleGeometry)this.box.Data).Rect.TopLeft,
                                    new Point(curPoint.X, ((RectangleGeometry)this.box.Data).Rect.Bottom))
                                };
                                break;
                            case EditType.Bottom:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(((RectangleGeometry)this.box.Data).Rect.TopLeft,
                                    new Point(((RectangleGeometry)this.box.Data).Rect.Right, curPoint.Y))
                                };
                                break;
                            case EditType.LeftTop:
                                this.box.Data = new RectangleGeometry { Rect = new Rect(curPoint, ((RectangleGeometry)this.box.Data).Rect.BottomRight) };
                                break;
                            case EditType.RightTop:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(new Point(((RectangleGeometry)this.box.Data).Rect.Left, curPoint.Y),
                                    new Point(curPoint.X, ((RectangleGeometry)this.box.Data).Rect.Bottom))
                                };
                                break;
                            case EditType.LeftBottom:
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(new Point(curPoint.X, ((RectangleGeometry)this.box.Data).Rect.Top),
                                     new Point(((RectangleGeometry)this.box.Data).Rect.Right, curPoint.Y))
                                };
                                break;
                            case EditType.RightBottom:
                                this.box.Data = new RectangleGeometry { Rect = new Rect(((RectangleGeometry)this.box.Data).Rect.TopLeft, curPoint) };
                                break;
                            case EditType.Internal:
                                double diffX = curPoint.X - this.downPoint.X;
                                double diffY = curPoint.Y - this.downPoint.Y;
                                this.box.Data = new RectangleGeometry
                                {
                                    Rect = new Rect(new Point(((RectangleGeometry)this.box.Data).Rect.Left + diffX, ((RectangleGeometry)this.box.Data).Rect.Top + diffY),
                                      new Point(((RectangleGeometry)this.box.Data).Rect.Right + diffX, ((RectangleGeometry)this.box.Data).Rect.Bottom + diffY))
                                };
                                this.downPoint = curPoint;
                                break;
                            case EditType.None:
                                break;
                        }
                        break;
                }
            }
        }
    }
}